package com.smmisia.article.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.Assert;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableList;
import com.smmisia.article.api.AuthService;
import com.smmisia.article.core.Recommend;
import com.smmisia.article.dto.article.ArticleAddRequest;
import com.smmisia.article.dto.article.ArticleDTO;
import com.smmisia.article.dto.article.ArticleHotResponse;
import com.smmisia.article.dto.article.ArticleUpdateDTO;
import com.smmisia.article.dto.likeFavorite.LikeFavoriteRequest;
import com.smmisia.article.dto.user.UserVO;
import com.smmisia.article.entity.Article;
import com.smmisia.article.entity.LikeFavorite;
import com.smmisia.article.entity.User;
import com.smmisia.article.entity.convetor.ArticleConvertor;
import com.smmisia.article.enums.ArticleCategoryEnum;
import com.smmisia.article.enums.StatusEnum;
import com.smmisia.article.es.entity.ArticleES;
import com.smmisia.article.es.mapper.ArticleEsMapper;
import com.smmisia.article.exception.customException;
import com.smmisia.article.mapper.ArticleMapper;
import com.smmisia.article.mapper.LikeFavoriteMapper;
import com.smmisia.article.response.RankResponse;
import com.smmisia.article.response.VisitorResponse;
import com.smmisia.article.response.article.ArticleResponse;
import com.smmisia.article.response.commentResponse;
import com.smmisia.article.service.ArticleService;
import com.smmisia.article.service.CommentService;
import com.smmisia.article.utils.ListToStringUtil;
import com.smmisia.article.utils.LoginUtil;
import com.smmisia.article.utils.easypoi.JDBCDruidUtils;
import com.smmisia.common.Result.Result;
import com.xxl.job.core.handler.annotation.XxlJob;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.dromara.easyes.core.biz.SAPageInfo;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.dromara.easyes.core.kernel.EsWrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.sql.Array;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.smmisia.article.enums.LikeEnum.LIKE_TYPE;
import static com.smmisia.article.enums.LikeEnum.UNLIKE_TYPE;

@Service
@Slf4j
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>
        implements ArticleService {

    private final String FOLLOW = "follow:user_id:";

    private final String VIEW = "view:";

    private final String VISITOR = "visitor";

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private Recommend recommend;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private LikeFavoriteMapper likeFavoriteMapper;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserServiceImpl userService;

    @Autowired
    private CommentService commentService;

    @Autowired
    private AuthService authService;

    @Autowired
    private ArticleEsMapper articleEsMapper;

    private static final String MUTUAL_FOLLOW = "mutual_follow:user_id:";

    private static final String ARTICLE_TIME_SEND = "article:time:send";

    private static final String FOLLOWING = "following:user_id:";

    private static final String FOLLOWS = "follows:user_id:";

    private static final String FEED = "feed:";

    private static final String TIMELINE = "timeline:";

    private static final String USER_ARTICLES = "user:articles:";

    private static final String ARTICLE = "article:";


    /**
     * 分页获取我的游记/攻略
     *
     * @param pageNum
     * @param pageSize
     * @param type
     * @return
     */
    @Override
    public Result<List<ArticleResponse>> listArticle(Integer pageNum, Integer pageSize, Integer id, Integer type) {

        String loginId = (String) StpUtil.getLoginId();
        Integer userId = Integer.valueOf(loginId);
        IPage<Article> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Article> wrapper = Wrappers.lambdaQuery();


        Integer queryUserId = (id == null) ? userId : id;
        wrapper.eq(Article::getUserId, queryUserId);
        wrapper.eq(Article::getType, type);

        // 如果 id 不为 null，但是查询用户不存在，则抛出异常
        if (id != null && authService.info(id) == null) {
            throw new customException("该用户不存在");
        }


        IPage<Article> articleIPage = articleMapper.selectPage(page, wrapper);
        List<Article> articles = articleIPage.getRecords();

        ArticleResponse article = getArticle(articles);
        return Result.ok(article);
    }

    /**
     * 新增文章
     *
     * @param articleAddRequest
     * @return
     */
    @Override
    public Result<String> add(ArticleAddRequest articleAddRequest) {
        //获取发布类型
        Integer type = articleAddRequest.getType();
        int insert;
        String loginId = (String) StpUtil.getLoginId();
        String address = (String) redisTemplate.opsForValue().get("ip:" + loginId);
        Article article = Article.create(articleAddRequest);
        article.setUserId(Integer.valueOf(loginId));
        article.setLocation(address);
        if (articleAddRequest.getPublishTime() != null) {
            article.setStatus(StatusEnum.UN_NORMAL_STATUS.getCode());
            insert = articleMapper.insert(article);
            Assert.notNull(insert > 0, () -> new customException("发布失败"));
            redisTemplate.opsForHash().put(ARTICLE_TIME_SEND, article.getId(), articleAddRequest.getPublishTime());
            return Result.ok("发布成功");
        }
        //普通发送
        article.setStatus(StatusEnum.NORMAL_STATUS.getCode());
        insert = articleMapper.insert(article);
        Assert.isTrue(insert > 0, () -> new customException("发布失败"));
        //如果不想使用redis，可以采用canal监听binlog实现同步增量到es
        List<Article> list = new ArrayList<>();
        list.add(article);
        ArticleResponse response = getArticle(list);
        //判断当前用户是否是大V用户
        Long isBig = redisTemplate.opsForSet().size(FOLLOWS + loginId);
        if (isBig < 10000) {
            Set members = redisTemplate.opsForSet().members(FOLLOWS + loginId);
            for (Object member : members) {
                Long l = redisTemplate.opsForList().rightPush(TIMELINE + member, article.getId());
            }
        }else {
            // 大V用户发布文章时，将文章ID存入其个人时间线
            redisTemplate.opsForList().rightPush(USER_ARTICLES + loginId, article.getId());
        }
        return Result.ok("发布成功");
    }

    @XxlJob(value = "sendArticle")
    public void sendArticle() {
        Map<String, String> entries = redisTemplate.opsForHash().entries(ARTICLE_TIME_SEND);
        LocalDateTime now = LocalDateTime.now();
        entries.forEach((articleId, sendTimeStr) -> {
            LocalDateTime sendTime = LocalDateTime.parse(sendTimeStr.toString(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            // 如果发送时间已经到达当前时间，处理该文章
            if (!sendTime.isAfter(now)) {
                Article article = articleMapper.selectById(articleId);
                article.setStatus(StatusEnum.NORMAL_STATUS.getCode());
                int result = articleMapper.updateById(article);
                Assert.notNull(result > 0, () -> new customException("定时发布失败"));
            }
        });
    }


    /**
     * 修改文章
     *
     * @param articleUpdateDTO
     * @return
     */
    @Override
    public Result<String> updateArticle(ArticleUpdateDTO articleUpdateDTO) {
        Integer loginId = (Integer) StpUtil.getLoginId();
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Article::getId, articleUpdateDTO.getId());
        wrapper.eq(Article::getUserId, loginId);
        Article articleById = articleMapper.selectOne(wrapper);
        Assert.notNull(articleById != null, () -> new customException("该文章不存在"));
        Article article = ArticleConvertor.INSTANCE.mapToArticle(articleUpdateDTO);
        //更新数据库
        int result = articleMapper.updateById(article);
        Assert.notNull(result > 0, () -> new customException("修改失败"));
        return Result.ok();
    }

    /**
     * 删除文章
     *
     * @param id
     * @return
     */
    @Override
    public Result<String> deletes(Integer id) {
        Integer loginId = (Integer) StpUtil.getLoginId();
        LambdaQueryWrapper<Article> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(Article::getId, id);
        wrapper.eq(Article::getUserId, loginId);
        int delete = articleMapper.delete(wrapper);
        Assert.notNull(delete > 0, () -> new customException("删除失败"));
        redisTemplate.delete(ARTICLE + id);
        return Result.ok("删除成功");
    }

    @Override
    public Result<String> hidden(Integer id) {
        Article article = articleMapper.selectById(id);

        if (article == null) {
            return Result.fail("文章不存在");
        }

        // 切换状态
        toggleArticleStatus(article);

        return Result.ok(article.getStatus().equals(StatusEnum.UN_NORMAL_STATUS.getCode()) ? "禁用成功" : "开启成功");
    }

    private void toggleArticleStatus(Article article) {
        if (article.getStatus().equals(StatusEnum.UN_NORMAL_STATUS.getCode())) {
            article.setStatus(StatusEnum.NORMAL_STATUS.getCode());
        } else {
            article.setStatus(StatusEnum.UN_NORMAL_STATUS.getCode());
        }
        articleMapper.updateById(article);
    }

    @Override
    public Result<List<ArticleResponse>> articleList(Integer pageNum, Integer pageSize) {
        IPage<Article> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Article> wrapper = Wrappers.lambdaQuery();
        List<Article> articles = articleMapper.selectPage(page, wrapper).getRecords();
        ArticleResponse article = getArticle(articles);
        return Result.ok(article);
    }

    @Override
    public Result<List<ArticleResponse>> articleById(Integer id) {
        //TODO 直接从es中查询
        Article article = articleMapper.selectById(id);
        if (article == null) {
            return Result.fail("该文章不存在");
        }

        ArticleDTO articleDTO = ArticleConvertor.INSTANCE.mapToArticleDTO(article);
        UserVO userInfo = getUserInfo(article);
        articleDTO.setUsername(userInfo.getUsername());
        List<String> imagesList = getImagesList(article.getImages());

        String tag = article.getTag();
        String[] resultArray = tag.split("#");
        List<String> resultList = new ArrayList<>();
        for (String s : resultArray) {
            if (!s.isEmpty()) {
                resultList.add("#" + s);
            }
        }
        // 设置标签
        articleDTO.setTagList(resultList);

        redisTemplate.opsForValue().increment(VIEW + article.getId(), 1);
        Integer view = (Integer) redisTemplate.opsForValue().get(VIEW + article.getId());
        articleDTO.setView(view);

        setUserLikeAndFavoriteStatus(articleDTO, id, String.valueOf(article.getUserId()));
        List<commentResponse> list = commentService.commentList(id, 0).getData();
        articleDTO.setUserInfo(userInfo);
        articleDTO.setImagesList(imagesList);
        articleDTO.setReviewList(list);
        articleDTO.setReview(list.size());
        return Result.ok(articleDTO);
    }

    private UserVO getUserInfo(Article article) {
        return userService.getUserInfoByUserId(article.getUserId());
    }

    private List<String> getImagesList(String images) {
        return ListToStringUtil.convertStringToList(images);
    }

    private void setUserLikeAndFavoriteStatus(ArticleDTO articleDTO, Integer articleId, String userId) {
        LambdaQueryWrapper<LikeFavorite> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(LikeFavorite::getArticleId, articleId);
        queryWrapper.eq(LikeFavorite::getUserId, Integer.valueOf(userId));

        LikeFavorite likeFavorite = likeFavoriteMapper.selectOne(queryWrapper);
        if (likeFavorite == null) {
            articleDTO.setLikeStatus(0);
            articleDTO.setFavoriteStatus(0);
        } else {
            articleDTO.setLikeStatus(likeFavorite.getLike());
            articleDTO.setFavoriteStatus(likeFavorite.getFavorite());
        }
    }

    @Override
    public Result<List<ArticleResponse>> articleFriendList() {
        // 1.获取当前用户
        Integer userId = Integer.valueOf((String) StpUtil.getLoginId());
        //2.获取相互关注用户id集合
        Set members = redisTemplate.opsForSet().members(MUTUAL_FOLLOW + userId);
        if (members.isEmpty()) {
            return Result.ok(Collections.emptyList());
        }
        ArticleResponse article = getArticle(members);
        return Result.ok(article);
    }

    @Override
    public Result<List<ArticleResponse>> articleFollowList() {
        String userId = (String) StpUtil.getLoginId();
        List<ArticleResponse> resultList = new ArrayList<>();

        // 1. 获取用户的关注列表
        Set<Integer> followings = redisTemplate.opsForSet().members(FOLLOWING + userId);
        if (followings == null || followings.isEmpty()) {
            return Result.ok(resultList);
        }

//        // 2. 分别处理大V和普通用户
//        for (Integer followId : followings) {
//            Long followerCount = redisTemplate.opsForSet().size(FOLLOWING + followId);
//
//            if (followerCount >= 10000) {
//                // 读扩散：实时获取大V的最新文章
//                List<Object> articleIds = redisTemplate.opsForList().range(USER_ARTICLES + followId, 0, 10);
//                if (articleIds != null && !articleIds.isEmpty()) {
//                    for (Object articleId : articleIds) {
//                        ArticleResponse article = (ArticleResponse) redisTemplate.opsForValue().get(FEED + articleId);
//                        if (article != null) {
//                            resultList.add(article);
//                        }
//                    }
//                }
//            } else {
//                // 写扩散：直接从Timeline获取
//                List<Object> articleIds = redisTemplate.opsForList().range(TIMELINE + followId, 0, 10);
//                if (articleIds != null && !articleIds.isEmpty()) {
//                    for (Object articleId : articleIds) {
//                        ArticleResponse article = (ArticleResponse) redisTemplate.opsForValue().get(FEED + articleId);
//                        if (article != null) {
//                            resultList.add(article);
//                        }
//                    }
//                }
//            }
//        }
        for (Integer followId : followings) {
            List<Integer> articleIds = redisTemplate.opsForList().range(TIMELINE + userId, 0, 10);
            //TODO 从es中查询
            List<Article> list = new ArrayList<>();
            //查询自己发布文章
            List<Article> lists = articleMapper.selectList(Wrappers.lambdaQuery(Article.class)
                    .eq(Article::getUserId,userId));
            list.addAll(lists);
            //查询出关注用户文章信息
            if(articleIds != null && !articleIds.isEmpty()){
                list  = articleMapper.selectBatchIds(articleIds);
            }

            ArticleResponse article = getArticle(list);
            resultList.add(article);
        }
        // 4. 限制返回条数
        return Result.ok(resultList.size() > 50 ? resultList.subList(0, 50) : resultList);
    }


    @Override
    public Result<List<ArticleResponse>> likeSearch(String keyword) {
        List<Article> articles = articleMapper.likeSearch(keyword);
        ArticleResponse article = getArticle(articles);
        return Result.ok(article);
    }

    @Override
    public Result<VisitorResponse> visitor() {
        redisTemplate.opsForValue().increment(VISITOR, 1);
        Integer visitor = (Integer) redisTemplate.opsForValue().get(VISITOR);
        VisitorResponse response = new VisitorResponse();
        response.setVisitor(visitor);
        long count = this.count();
        response.setArticle(count);
        response.setReviews(commentService.count());
        return Result.ok(response);
    }

//    @Override
//    public Result<List<RankResponse>> rank() {
//        // 获取所有文章列表（假设已经获取到文章列表）
//        List<Article> articleList = articleMapper.selectList(new LambdaQueryWrapper<Article>());
//
//        // 通过 userId 分组并计算每个用户的文章数量
//        Map<Integer, Long> userArticleCount = articleList.stream()
//                .collect(Collectors.groupingBy(Article::getUserId, Collectors.counting()));
//
//        // 根据 userId 查询用户的昵称和头像，并封装到 RankResponse 中
//        List<RankResponse> rankList = userArticleCount.entrySet().stream()
//                .map(entry -> {
//                    Integer userId = entry.getKey();
//                    Long articleCount = entry.getValue();
//
//                    // 查询用户信息
//                    User user = userMapper.selectById(userId);
//
//                    // 创建 RankResponse 并填充数据
//                    RankResponse rankResponse = new RankResponse();
//                    rankResponse.setId(userId);
//                    rankResponse.setUsername(user.getUsername()); // 假设 User 类中有 username
//                    rankResponse.setAvatar(user.getAvatar()); // 假设 User 类中有 avatar
//                    rankResponse.setCount(articleCount.intValue());
//
//                    return rankResponse;
//                })
//                .collect(Collectors.toList());
//
//        return Result.ok(rankList);
//    }

    @Override
    public Result<List<RankResponse>> rank() {
        List<Map<String, Object>> rank = articleMapper.getUserArticleRank();
        // 映射查询结果到 RankResponse
        List<RankResponse> rankList = rank.stream()
                .map(row -> {
                    Integer userId = (Integer) row.get("user_id");
                    Integer articleCount = ((Long) row.get("article_count")).intValue(); // 将 Long 转为 Integer

                    // 查询用户信息
                    User user = authService.info(userId);

                    RankResponse rankResponse = new RankResponse();
                    rankResponse.setId(userId);
                    rankResponse.setUsername(user.getUsername()); // 设置用户名
                    rankResponse.setAvatar(user.getAvatar()); // 设置用户头像
                    rankResponse.setCount(articleCount); // 设置文章数量

                    return rankResponse;
                })
                .collect(Collectors.toList());
        //只返回前10条数据
        rankList = rankList.subList(0, Math.min(rankList.size(), 10));
        return Result.ok(rankList);
    }

    @Override
    public Result<List<ArticleResponse>> article(Integer pageNum, Integer pageSize, Integer id) {
        String loginId = (String) StpUtil.getLoginId();
        Integer userId = Integer.valueOf(loginId);
        IPage<Article> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Article> wrapper = Wrappers.lambdaQuery();


        Integer queryUserId = (id == null) ? userId : id;
        wrapper.eq(Article::getUserId, queryUserId);

        // 如果 id 不为 null，但是查询用户不存在，则抛出异常
        if (id != null && authService.info(id) == null) {
            throw new customException("该用户不存在");
        }


        IPage<Article> articleIPage = articleMapper.selectPage(page, wrapper);
        List<Article> articles = articleIPage.getRecords();

        ArticleResponse article = getArticle(articles);
        return Result.ok(article);
    }

    @Override
    public Result<List<ArticleResponse>> articleEs(String keyword,Integer pageNum,Integer pageSize,Integer lastId) {
        LambdaEsQueryWrapper<ArticleES> wrapper = new LambdaEsQueryWrapper<>(ArticleES.class);
        wrapper.eq(ArticleES::getTitle, keyword)
                .or()
                .match(ArticleES::getContent, keyword)
                .match(ArticleES::getDeleted,"0")
                .orderByDesc(ArticleES::getCreateTime);
        SAPageInfo<ArticleES> saPageInfo;
        if(lastId==null){
            saPageInfo = articleEsMapper.searchAfterPage(wrapper,null,pageSize);
        }else {
            saPageInfo = articleEsMapper.searchAfterPage(wrapper, ImmutableList.of(lastId),10);
        }
        List<ArticleES> list = saPageInfo.getList();
        List<Article> articles = ArticleConvertor.INSTANCE.mapToEntity(list);
        ArticleResponse article = getArticle(articles);
        return Result.ok(article);
    }


    public ArticleResponse getArticle(Set members) {
        List<Integer> list = (List<Integer>) members.stream().collect(Collectors.toList());
        List<User> userIdList = list.stream().map(id -> {
                    User user = authService.info(id);
                    return user;
                }
        ).collect(Collectors.toList());
        // 获取 userIdList 中的所有 userId
        List<Integer> userIds = userIdList.stream()
                .map(User::getId) // 提取 User 对象的 id
                .collect(Collectors.toList());

        // 创建 LambdaQueryWrapper 查询 Article 表
        LambdaQueryWrapper<Article> articleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        articleLambdaQueryWrapper.in(Article::getUserId, userIds); // 使用 in 查询所有 userId 的文章

        // 查询符合条件的文章列表
        List<Article> articles = articleMapper.selectList(articleLambdaQueryWrapper);

        ArticleResponse article = getArticle(articles);
        return article;
    }

    /**
     * 获取热门文章
     *
     * @return
     */
    @Override
    public Result<ArticleHotResponse> hotspot() {
        //TODO 缺少收藏数量
        String loginId = LoginUtil.getLoginId();
        List<Article> articleList = recommend.userCfRecommend(Integer.valueOf(loginId));
        //List<ArticleHotResponse> convert = BeanUtil.convert(articleList, ArticleHotResponse.class);
        return Result.ok(null);
    }

    /**
     * 文章点赞/取消点赞
     *
     * @param likeFavoriteRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> like(LikeFavoriteRequest likeFavoriteRequest) {
        String loginId = (String) StpUtil.getLoginId();
        Integer userId = Integer.valueOf(loginId);
        Integer articleId = likeFavoriteRequest.getArticleId();
        LambdaQueryWrapper<LikeFavorite> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LikeFavorite::getArticleId, articleId)
                .eq(LikeFavorite::getUserId, userId);
        LikeFavorite likeFavorite = likeFavoriteMapper.selectOne(wrapper);
        if (likeFavorite == null) {
            likeFavorite = new LikeFavorite();
            likeFavorite.setUserId(userId);
            likeFavorite.setArticleId(articleId);
            likeFavorite.setLike(LIKE_TYPE.getCode());
            likeFavorite.setFavorite(UNLIKE_TYPE.getCode());
            int result = likeFavoriteMapper.insert(likeFavorite);
            LambdaUpdateWrapper<Article> articleWrapper = new LambdaUpdateWrapper<>();
            articleWrapper.eq(Article::getId, articleId);
            articleWrapper.setSql("liked = liked + 1");
            int update = articleMapper.update(null, articleWrapper);
            Assert.notNull(result > 0, () -> new customException("点赞失败"));
            return Result.ok("点赞成功");
        }
        if (likeFavorite.getLike() == LIKE_TYPE.getCode()) {
            likeFavorite.setLike(UNLIKE_TYPE.getCode());
            int result = likeFavoriteMapper.updateById(likeFavorite);
            Assert.notNull(result > 0, () -> new customException("取消点赞失败"));
            LambdaUpdateWrapper<Article> articleWrapper = new LambdaUpdateWrapper<>();
            articleWrapper.eq(Article::getId, articleId);
            articleWrapper.setSql("liked = liked - 1");
            int update = articleMapper.update(null, articleWrapper);
            Assert.notNull(update > 0, () -> new customException("取消点赞失败"));
            return Result.ok("取消点赞成功");
        } else {
            likeFavorite.setLike(LIKE_TYPE.getCode());
            int result = likeFavoriteMapper.updateById(likeFavorite);
            Assert.notNull(result > 0, () -> new customException("点赞失败"));
            LambdaUpdateWrapper<Article> articleWrapper = new LambdaUpdateWrapper<>();
            articleWrapper.eq(Article::getId, articleId);
            articleWrapper.setSql("liked = liked + 1");
            int update = articleMapper.update(null, articleWrapper);
            Assert.notNull(update > 0, () -> new customException("点赞失败"));
            return Result.ok("点赞成功");
        }

    }

    /**
     * 文章收藏
     *
     * @param likeFavoriteRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> favorite(LikeFavoriteRequest likeFavoriteRequest) {
        String loginId = (String) StpUtil.getLoginId();
        Integer userId = Integer.valueOf(loginId);
        Integer articleId = likeFavoriteRequest.getArticleId();
        LambdaQueryWrapper<LikeFavorite> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LikeFavorite::getArticleId, articleId)
                .eq(LikeFavorite::getUserId, userId);
        LikeFavorite likeFavorite = likeFavoriteMapper.selectOne(wrapper);
        if (likeFavorite == null) {
            likeFavorite = new LikeFavorite();
            likeFavorite.setUserId(userId);
            likeFavorite.setArticleId(articleId);
            likeFavorite.setFavorite(LIKE_TYPE.getCode());
            likeFavorite.setLike(UNLIKE_TYPE.getCode());
            int insert = likeFavoriteMapper.insert(likeFavorite);
            Assert.notNull(insert > 0, () -> new customException("收藏失败"));
            LambdaUpdateWrapper<Article> articleWrapper = new LambdaUpdateWrapper<>();
            articleWrapper.eq(Article::getId, articleId);
            articleWrapper.setSql("liked = liked + 1");
            int update = articleMapper.update(null, articleWrapper);
            Assert.notNull(update > 0, () -> new customException("点赞失败"));
            return Result.ok("收藏成功");
        }
        if (likeFavorite.getFavorite() == LIKE_TYPE.getCode()) {
            likeFavorite.setFavorite(UNLIKE_TYPE.getCode());
            int result = likeFavoriteMapper.updateById(likeFavorite);
            Assert.notNull(result > 0, () -> new customException("取消收藏失败"));
            LambdaUpdateWrapper<Article> articleWrapper = new LambdaUpdateWrapper<>();
            articleWrapper.eq(Article::getId, articleId);
            articleWrapper.setSql("favorite = favorite - 1");
            int update = articleMapper.update(null, articleWrapper);
            Assert.notNull(update > 0, () -> new customException("取消收藏失败"));
            return Result.ok("取消点赞成功");
        } else {
            likeFavorite.setFavorite(LIKE_TYPE.getCode());
            int result = likeFavoriteMapper.updateById(likeFavorite);
            Assert.notNull(result > 0, () -> new customException("收藏失败"));
            LambdaUpdateWrapper<Article> articleWrapper = new LambdaUpdateWrapper<>();
            articleWrapper.eq(Article::getId, articleId);
            articleWrapper.setSql("favorite = favorite + 1");
            int update = articleMapper.update(null, articleWrapper);
            Assert.notNull(update > 0, () -> new customException("收藏失败"));
            return Result.ok("点赞成功");
        }
    }


    /**
     * 获取我的点赞收藏列表详情
     *
     * @param
     * @return type 0 获取点赞文章
     * type 1 获取收藏文章
     */
    @Override
    public Result<List<ArticleResponse>> likeInfo(Integer id, Integer pageNum, Integer pageSize, Integer type) {
        // 获取当前登录用户的ID
        Integer userId = (id == null) ? getCurrentUserId() : id;

        // 验证用户是否存在
        validateUser(userId);

        LambdaQueryWrapper<LikeFavorite> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LikeFavorite::getUserId, userId);

        // 根据 type 来判断查询点赞还是收藏
        if (type.equals(0)) {
            wrapper.eq(LikeFavorite::getLike, 1);  // 点赞
        } else {
            wrapper.eq(LikeFavorite::getFavorite, 1);  // 收藏
        }

        // 查询并获取文章信息
        ArticleResponse articles = getArticlesByLikeFavorite(wrapper);
        if (articles == null) {
            ArticleResponse response = new ArticleResponse();
            response.setList(new ArrayList<>());
            return Result.ok(response);
        }
        return Result.ok(articles);
    }

    /**
     * 获取当前登录用户ID
     */
    private Integer getCurrentUserId() {
        String loginId = (String) StpUtil.getLoginId();
        return Integer.valueOf(loginId);
    }

    /**
     * 验证用户是否存在
     */
    private void validateUser(Integer userId) {
        User user = authService.info(userId);
        if (user == null) {
            throw new customException("该用户不存在");
        }
    }

    /**
     * 根据查询条件获取关联的文章信息
     */
    private ArticleResponse getArticlesByLikeFavorite(LambdaQueryWrapper<LikeFavorite> wrapper) {
        List<LikeFavorite> likeFavorites = likeFavoriteMapper.selectList(wrapper);
        List<Integer> articleIds = likeFavorites.stream()
                .map(LikeFavorite::getArticleId)
                .collect(Collectors.toList());

        if (articleIds.isEmpty()) {
            return null;  // 如果没有文章ID，返回空列表
        }

        List<Article> articles = articleMapper.selectBatchIds(articleIds);
        return getArticle(articles);  // 调用已有方法转换为 ArticleVO
    }


    public ArticleResponse getArticle(List<Article> articles) {

        log.info("当前用户id:"+articles.toString());

        Map<Integer, String> userIdToUsernameMap = articles.stream()
                .map(Article::getUserId)
                .distinct()
                .collect(Collectors.toMap(
                        userId -> userId,
                        userId -> {
                            User user = authService.info(userId);
                            log.info("当前用户id:"+user.toString());
                            return user != null ? user.getUsername() : null;
                        }
                ));

        // 将 Article 转换为 ArticleDTO 并设置 username
        List<ArticleDTO> result = articles.stream().map(article -> {
            ArticleDTO articleDTO = ArticleConvertor.INSTANCE.mapToArticleDTO(article);
            String tag = article.getTag();
            String[] resultArray = tag.split("#");
            List<String> resultList = new ArrayList<>();
            for (String s : resultArray) {
                if (!s.isEmpty()) {
                    resultList.add("#" + s);
                }
            }
            // 设置标签
            articleDTO.setTagList(resultList);
            //设置浏览量
            Integer view = (Integer) redisTemplate.opsForValue().get(VIEW + article.getId());
            articleDTO.setView(view);

            String username = userIdToUsernameMap.get(article.getUserId());
            String images = article.getImages();
            List<String> imagesList = ListToStringUtil.convertStringToList(images);
            //获取用户信息
            UserVO dto = userService.getUserInfoByUserId(article.getUserId());
            //获取用户点赞数据
            String userId = (String) StpUtil.getLoginId();
            Integer id = article.getId();

            LambdaQueryWrapper<LikeFavorite> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(LikeFavorite::getArticleId, id);
            queryWrapper.eq(LikeFavorite::getUserId, Integer.valueOf(userId));
            LikeFavorite likeFavorite = likeFavoriteMapper.selectOne(queryWrapper);

            if (likeFavorite == null) {
                //说明用户无点赞收藏数据
                articleDTO.setLikeStatus(0);
                articleDTO.setFavoriteStatus(0);
            } else {
                articleDTO.setLikeStatus(likeFavorite.getLike());
                articleDTO.setFavoriteStatus(likeFavorite.getFavorite());
            }
            List<commentResponse> list = commentService.commentList(id, 0).getData();

            articleDTO.setUsername(username);
            articleDTO.setImagesList(imagesList);
            articleDTO.setReviewList(list);
            articleDTO.setReview(list.size());
            articleDTO.setUserInfo(dto);
            return articleDTO;

        }).collect(Collectors.toList());
        ArticleResponse articleResponse = new ArticleResponse();
        articleResponse.setList(result);
        return articleResponse;
    }

    /**
     * 多线程文章导出
     *
     * @param response
     * @throws IOException
     */
    @Override
    public void export(HttpServletResponse response) throws IOException {
        OutputStream outputStream = response.getOutputStream();
        long start = System.currentTimeMillis();
        System.out.println("-----------任务执行开始-----------");
        // 设置响应内容
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("UTF-8");// 防止下载的文件名字乱码
        try {
            // 文件以附件形式下载
            response.setHeader("Content-disposition",
                    "attachment;filename=down_" + URLEncoder.encode(System.currentTimeMillis() + ".xlsx", "utf-8"));
            //获取总数据量
            long count = this.count();
            //每页多少个
            int pageSize = 10000;
            //必须放到循环外，否则会刷新流
            ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
            List<CompletableFuture> completableFutures = new ArrayList<>();
            for (int i = 0; i < (count / pageSize) + 1; i++) {
                int finalI = i;
                CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
                    List<Article> exportList = articleMapper.findLimit(finalI * pageSize, pageSize);
                    if (!CollectionUtils.isEmpty(exportList)) {
                        WriteSheet writeSheet = EasyExcel.
                                writerSheet(finalI, "用户" + (finalI + 1)).head(User.class)
                                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
                        synchronized (excelWriter) {
                            excelWriter.write(exportList, writeSheet);
                        }
                    }
                }, new ThreadPoolExecutor(10, 10, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000)));
                completableFutures.add(completableFuture);
            }
            for (CompletableFuture completableFuture : completableFutures) {
                completableFuture.join();
            }
            //刷新流
            excelWriter.finish();

            System.out.println("本次导出execl任务执行完毕,共消耗：  " + (System.currentTimeMillis() - start) + "ms");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        outputStream.flush();
        response.getOutputStream().close();
    }

    /**
     * 单线程文章导出
     *
     * @param response
     * @throws IOException
     */
    @Override
    public void newExport(HttpServletResponse response) throws IOException {
        OutputStream outputStream = response.getOutputStream();
        long start = System.currentTimeMillis();
        System.out.println("-----------任务执行开始-----------");
        // 设置响应内容
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("UTF-8");// 防止下载的文件名字乱码
        try {
            // 文件以附件形式下载
            response.setHeader("Content-disposition",
                    "attachment;filename=down_" + URLEncoder.encode(System.currentTimeMillis() + ".xlsx", "utf-8"));
            //获取总数据量
            int count = (int) this.count();
            //每页多少个
            int pageSize = 1000000;
            //必须放到循环外，否则会刷新流
            ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
            //先查询第一页
            List<Article> exportList = articleMapper.findNewPage(null, pageSize);
            if (CollectionUtils.isEmpty(exportList)) {
                throw new RuntimeException("数据库没有数据");
            }
            WriteSheet writeSheet = EasyExcel.writerSheet(0, "用户" + 1).head(User.class)
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
            excelWriter.write(exportList, writeSheet);

            Article article = exportList.get(exportList.size() - 1);
            for (int i = 1; i < (count / pageSize) + 1; i++) {
                exportList = articleMapper.findNewPage(String.valueOf(article.getId()), pageSize);
                if (CollectionUtils.isEmpty(exportList)) {
                    break;
                }
                writeSheet = EasyExcel.writerSheet(i, "用户" + (i + 1)).head(User.class)
                        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
                excelWriter.write(exportList, writeSheet);
                article = exportList.get(exportList.size() - 1);
            }
            //刷新流
            excelWriter.finish();

            System.out.println("本次导出execl任务执行完毕,共消耗：  " + (System.currentTimeMillis() - start) + "ms");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        outputStream.flush();
        response.getOutputStream().close();
    }

    /**
     * 插入100w数据到数据库
     *
     * @param dataList
     * @return
     */
    @Override
    public Map<String, Object> importDBFromExcel10w(List<Map<Integer, String>> dataList) {
        HashMap<String, Object> result = new HashMap<>();
        //结果集中数据为0时,结束方法.进行下一次调用
        if (dataList.size() == 0) {
            result.put("empty", "0000");
            return result;
        }
        //JDBC分批插入+事务操作完成对10w数据的插入
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            long startTime = System.currentTimeMillis();
            log.info(dataList.size() + "条,开始导入到数据库时间:" + startTime + "ms");
            conn = dataSource.getConnection();
            //控制事务:默认不提交
            conn.setAutoCommit(false);
            String sql = "insert into usernew (id,name,phone,ceate_by) values (?,?,?,?)";
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < dataList.size(); i++) {
                Map<Integer, String> item = dataList.get(i);
                ps.setString(1, item.get(0));
                ps.setString(2, item.get(1));
                ps.setString(3, item.get(2));
                ps.setString(4, item.get(3));

                //将一组参数添加到此 PreparedStatement 对象的批处理命令中。
                ps.addBatch();
            }
            //执行批处理
            ps.executeBatch();
            //手动提交事务
            conn.commit();
            long endTime = System.currentTimeMillis();
            log.info(dataList.size() + "条,结束导入到数据库时间:" + endTime + "ms");
            log.info(dataList.size() + "条,导入用时:" + (endTime - startTime) + "ms");
            result.put("success", "1111");
        } catch (Exception e) {
            result.put("exception", "0000");
            e.printStackTrace();
        } finally {
            //关连接
            JDBCDruidUtils.close(conn, ps);
        }
        return result;
    }

    /**
     * 查询所有攻略
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Result<List<ArticleResponse>> listArticleNotes(Integer pageNum, Integer pageSize) {
        IPage<Article> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Article> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(Article::getType, ArticleCategoryEnum.ARTICLE_CATEGORY_NOTES.getCode());
        List<Article> articles = articleMapper.selectPage(page, wrapper).getRecords();

        ArticleResponse article = getArticle(articles);
        return Result.ok(article);
    }


    /**
     * 查询所有游记
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Result<List<ArticleResponse>> listArticleStrategy(Integer pageNum, Integer pageSize) {
        IPage<Article> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Article> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(Article::getType, ArticleCategoryEnum.ARTICLE_CATEGORY_STRATEGY.getCode());
        List<Article> articles = articleMapper.selectPage(page, wrapper).getRecords();
        ArticleResponse article = getArticle(articles);
        return Result.ok(article);
    }

}